#include "Inf_FourwayKey.h"

#include "FreeRTOS.h"
#include "task.h"

/* 按键长按时间阈值（单位：10ms） */
#define KEY_LONG_PRESS_THRESHOLD 100 // 1秒

/* 按键消抖时间（单位：10ms） */
#define KEY_DEBOUNCE_TIME 3 // 30ms

/* 连续模式默认触发间隔（单位：10ms） */
#define KEY_CONTINUOUS_INTERVAL 20 // 200ms

/* ADC采样间隔（单位：ms） */
#define ADC_SAMPLE_INTERVAL 20

/* ADC电压阈值定义 */
#define KEY_VOLTAGE_NONE_MIN   4900 // 无按键最小电压 (mV)
#define KEY_VOLTAGE_NONE_MAX   5000 // 无按键最大电压 (mV)
#define KEY_VOLTAGE_UP_MIN     640  // 上键最小电压 (mV)
#define KEY_VOLTAGE_UP_MAX     660  // 上键最大电压 (mV)
#define KEY_VOLTAGE_DOWN_MIN   1400 // 下键最小电压 (mV)
#define KEY_VOLTAGE_DOWN_MAX   1500 // 下键最大电压 (mV)
#define KEY_VOLTAGE_LEFT_MIN   90   // 左键最小电压 (mV)
#define KEY_VOLTAGE_LEFT_MAX   100  // 左键最大电压 (mV)
#define KEY_VOLTAGE_RIGHT_MIN  280  // 右键最小电压 (mV)
#define KEY_VOLTAGE_RIGHT_MAX  300  // 右键最大电压 (mV)
#define KEY_VOLTAGE_MIDDLE_MIN 0    // 中键最小电压 (mV)
#define KEY_VOLTAGE_MIDDLE_MAX 10   // 中键最大电压 (mV)

static void      Inf_ForewayKey_DisplayPressedKeyType(KeyType_e keyType);
static KeyType_e Inf_FourwayKey_GetKeyTypeByVoltage(uint32_t voltage);
static void      Inf_FourwayKey_StateMachine(KeyType_e keyType, bool isPressed);
static void      Inf_FourwayKey_KeyModeNoneCallback(KeyType_e keyType, KeyEvent_e keyEvent);
static void      Inf_FourwayKey_KeyModeMassageCallback(KeyType_e keyType, KeyEvent_e keyEvent);
static void      Inf_FourwayKey_KeyModeFlankCallback(KeyType_e keyType, KeyEvent_e keyEvent);
static void      Inf_FourwayKey_KeyModeLumbarSupportCallback(KeyType_e keyType, KeyEvent_e keyEvent);

/* 按键配置 */
KeyConfig keyConfig = {
    .keyWorkMode = KEY_WORK_MODE_NONE,
};

/* 按键状态数组 */
static KeyStatus_t keyStatus[KEY_TYPE_MAX];

/* 按键回调函数 */
static KeyCallback_t keyCallback = NULL;

/* 当前检测到的按键类型 */
// static KeyType_e currentKeyType = KEY_TYPE_NONE;

/* 上次采样时间 */
static uint32_t lastSampleTime = 0;

/* 连续模式触发间隔 */
static uint32_t continuousInterval = KEY_CONTINUOUS_INTERVAL;

/**
 * @brief 初始化四向按键
 */
void Inf_FourwayKey_Init(void)
{
    /* 初始化ADC */
    Driver_ADC_Init();

    /* 初始化按键状态 */
    for (int i = 0; i < KEY_TYPE_MAX; i++) {
        keyStatus[i].state          = KEY_STATE_IDLE;
        keyStatus[i].event          = KEY_EVENT_NONE;
        keyStatus[i].pressTime      = 0;
        keyStatus[i].isPressed      = false;
        keyStatus[i].mode           = KEY_MODE_SINGLE; // 默认为单次模式
        keyStatus[i].continuousTime = 0;
    }

    /* 配置5个按键, 初始为单次模式 */
    for (uint8_t i = KEY_TYPE_UP; i < KEY_TYPE_MAX; i++) {
        Inf_FourwayKey_SetMode((KeyType_e)i, KEY_MODE_SINGLE);
    }

    /* 设置连续触发间隔为10ms */
    Inf_FourwayKey_SetContinuousInterval(0);

    /* 创建按键队列 */
    keyReceiveQueue = xQueueCreate(KEY_RECEIVE_QUEUE_SIZE, sizeof(KeyType_e));
    if (keyReceiveQueue == NULL) {
        LOG("Create keyReceiveQueue failed!\n");
    }

    /* 启动第一次ADC采样 */
    Driver_ADC_StartSample(ADC_CHANNEL_KEY);
}

/**
 * @brief 注册按键回调函数
 *
 * @param callback 回调函数指针
 */
void Inf_FourwayKey_RegisterCallback(KeyCallback_t callback) { keyCallback = callback; }

/**
 * @brief 按键定时处理函数
 *
 * @note 在定时器中断中调用，建议10ms调用一次
 */
void Inf_FourwayKey_TimerHandler(void)
{
    uint32_t currentTime = xTaskGetTickCount();

    /* 定期进行ADC采样 */
    if ((currentTime - lastSampleTime) >= ADC_SAMPLE_INTERVAL) {
        Driver_ADC_StartSample(ADC_CHANNEL_KEY);
        lastSampleTime = currentTime;
    }

    /* 获取ADC电压值 */
    uint32_t voltage = Driver_ADC_GetVoltage(ADC_CHANNEL_KEY);

    /* 根据电压值判断按键类型 */
    KeyType_e keyType = Inf_FourwayKey_GetKeyTypeByVoltage(voltage);

    /* 更新当前按键类型 */
    // currentKeyType = keyType;

    /* 处理所有按键的状态机 */
    for (uint8_t i = 1; i < KEY_TYPE_MAX; i++) { // 从1开始，跳过KEY_TYPE_NONE
        bool isPressed = (keyType == i);
        Inf_FourwayKey_StateMachine((KeyType_e)i, isPressed);
    }
}

/**
 * @brief 获取按键状态
 *
 * @param keyType 按键类型
 * @return true 按键被按下
 * @return false 按键未被按下
 */
bool Inf_FourwayKey_GetState(KeyType_e keyType)
{
    if (keyType == KEY_TYPE_NONE || keyType >= KEY_TYPE_MAX) {
        return false;
    }

    return keyStatus[keyType].isPressed;
}

/**
 * @brief 获取按键事件
 *
 * @param keyType 按键类型
 * @return KeyEvent_e 按键事件
 */
KeyEvent_e Inf_FourwayKey_GetEvent(KeyType_e keyType)
{
    if (keyType == KEY_TYPE_NONE || keyType >= KEY_TYPE_MAX) {
        return KEY_EVENT_NONE;
    }

    return keyStatus[keyType].event;
}

/**
 * @brief 清除按键事件
 *
 * @param keyType 按键类型
 */
void Inf_FourwayKey_ClearEvent(KeyType_e keyType)
{
    if (keyType == KEY_TYPE_NONE || keyType >= KEY_TYPE_MAX) {
        return;
    }

    keyStatus[keyType].event = KEY_EVENT_NONE;
}

/**
 * @brief 设置按键模式
 *
 * @param keyType 按键类型
 * @param mode 按键模式
 */
void Inf_FourwayKey_SetMode(KeyType_e keyType, KeyMode_e mode)
{
    if (keyType == KEY_TYPE_NONE || keyType >= KEY_TYPE_MAX) {
        return;
    }

    keyStatus[keyType].mode = mode;
}

/**
 * @brief 获取按键模式
 *
 * @param keyType 按键类型
 * @return KeyMode_e 按键模式
 */
KeyMode_e Inf_FourwayKey_GetMode(KeyType_e keyType)
{
    if (keyType == KEY_TYPE_NONE || keyType >= KEY_TYPE_MAX) {
        return KEY_MODE_SINGLE;
    }

    return keyStatus[keyType].mode;
}

/**
 * @brief 设置连续模式触发间隔
 *
 * @param interval 触发间隔（单位：10ms）
 */
void Inf_FourwayKey_SetContinuousInterval(uint32_t interval)
{
    // if (interval >= 0) {
    continuousInterval = interval;
    // }
}

/**
 * @brief 选择按键回调函数
 *
 * @param keyWorkMode 按键工作模式
 */
void Inf_FourwayKey_SelectKeyCallback(KeyWorkMode_e keyWorkMode)
{
    static KeyWorkMode_e lastKeyWorkMode = KEY_WORK_MODE_NONE;

    switch (keyWorkMode) {
    case KEY_WORK_MODE_NONE:           keyCallback = Inf_FourwayKey_KeyModeNoneCallback; break;
    case KEY_WORK_MODE_MASSAGE:        keyCallback = Inf_FourwayKey_KeyModeMassageCallback; break;
    case KEY_WORK_MODE_FLANK:          keyCallback = Inf_FourwayKey_KeyModeFlankCallback; break;
    case KEY_WORK_MODE_LUMBAR_SUPPORT: keyCallback = Inf_FourwayKey_KeyModeLumbarSupportCallback; break;
    default:                           LOG("keyWorkMode error\n"); break;
    }

    /* 切换模式时 重置按键队列 */
    if (lastKeyWorkMode != keyWorkMode) {
        /* 清空按键队列 */
        if (xQueueReset(keyReceiveQueue) != pdPASS) {
            LOG("xQueueReset(keyReceiveQueue) failed!\n");
        }
        lastKeyWorkMode = keyWorkMode;
    }

    Inf_FourwayKey_RegisterCallback(keyCallback);
}

/**
 * @brief 按键模式-腰托模式下的按键回调函数
 *
 * @param keyType   按键类型
 * @param keyEvent  按键事件
 */
static void Inf_FourwayKey_KeyModeLumbarSupportCallback(KeyType_e keyType, KeyEvent_e keyEvent)
{
    /* 将不为空的按键发送到 keyReceiveQueue 中 */
    if (keyType == KEY_TYPE_NONE) {
        return;
    }

    if (keyType == KEY_TYPE_MIDDLE) {

        /* 将所有按键都设置为单次模式, 因为按摩模式均为 单次模式 */
        for (uint8_t i = KEY_TYPE_UP; i < KEY_TYPE_MAX; i++) {
            Inf_FourwayKey_SetMode((KeyType_e)i, KEY_MODE_SINGLE);
        }

        keyConfig.keyWorkMode = KEY_WORK_MODE_NONE;

        LOG("KEY MODE (LUMBAR_SUPPORT->NONE)\n");
    }

    Inf_ForewayKey_DisplayPressedKeyType(keyType);

    if (xQueueSend(keyReceiveQueue, &keyType, 0) == errQUEUE_FULL) {
        LOG("xQueueSend(keyReceiveQueue) failed!\n");
    }
}

/**
 * @brief 按键模式-被动侧翼模式下的按键回调函数
 *
 * @param keyType   按键类型
 * @param keyEvent  按键事件
 */
static void Inf_FourwayKey_KeyModeFlankCallback(KeyType_e keyType, KeyEvent_e keyEvent)
{
    /* 将不为空的按键发送到 keyReceiveQueue 中 */
    if (keyType == KEY_TYPE_NONE) {
        return;
    }

    if (keyType == KEY_TYPE_MIDDLE) {
        /* 关闭所有的阀门 */
        App_Flank_Stop();

        /* 将除中键按键都设置为连续模式, 因为侧翼模式均为 连续模式 */
        for (uint8_t i = KEY_TYPE_UP; i < KEY_TYPE_MIDDLE; i++) {
            Inf_FourwayKey_SetMode((KeyType_e)i, KEY_MODE_CONTINUOUS);
        }

        keyConfig.keyWorkMode = KEY_WORK_MODE_LUMBAR_SUPPORT;

        LOG("KEY MODE (FLANK->LUMBAR_SUPPORT)\n");
    }

    Inf_ForewayKey_DisplayPressedKeyType(keyType);

    if (xQueueSend(keyReceiveQueue, &keyType, 0) == errQUEUE_FULL) {
        LOG("xQueueSend(keyReceiveQueue) failed!\n");
    }
}

/**
 * @brief 按键模式-按摩模式下的按键回调函数
 *
 * @param keyType   按键类型
 * @param keyEvent  按键事件
 */
static void Inf_FourwayKey_KeyModeMassageCallback(KeyType_e keyType, KeyEvent_e keyEvent)
{
    /* 将不为空的按键发送到 keyReceiveQueue 中 */
    if (keyType == KEY_TYPE_NONE) {
        return;
    }

    if (keyType == KEY_TYPE_MIDDLE && keyEvent == KEY_EVENT_SHORT_PRESS) {
        /* 立即关闭按摩 */
        massageConfig.isMassageOn = false;

        /* 将除中键按键都设置为连续模式, 因为侧翼模式均为 连续模式 */
        for (uint8_t i = KEY_TYPE_UP; i < KEY_TYPE_MIDDLE; i++) {
            Inf_FourwayKey_SetMode((KeyType_e)i, KEY_MODE_CONTINUOUS);
        }

        keyConfig.keyWorkMode = KEY_WORK_MODE_FLANK;

        LOG("KEY MODE (MASSAGE->FLANK)\n");
    }

    Inf_ForewayKey_DisplayPressedKeyType(keyType);

    if (xQueueSend(keyReceiveQueue, &keyType, 0) == errQUEUE_FULL) {
        LOG("xQueueSend(keyReceiveQueue) failed!\n");
    }
}

/**
 * @brief 按键模式-未定义模式下的按键回调函数
 *
 * @param keyType   按键类型
 * @param keyEvent  按键事件
 */
static void Inf_FourwayKey_KeyModeNoneCallback(KeyType_e keyType, KeyEvent_e keyEvent)
{
    if (keyType == KEY_TYPE_MIDDLE) {
        /* 中键按下，切换按键工作模式 */
        keyConfig.keyWorkMode = KEY_WORK_MODE_MASSAGE;

        /* 开始计时15min */
        massageConfig.massageResidueTime = MASSAGE_MAX_TIME;

        /* 将所有按键都设置为单次模式, 因为按摩模式均为 单次模式 */
        for (uint8_t i = KEY_TYPE_UP; i < KEY_TYPE_MAX; i++) {
            Inf_FourwayKey_SetMode((KeyType_e)i, KEY_MODE_SINGLE);
        }

        massageConfig.isMassageOn = true;

        LOG("KEY MODE (NONE->MASSAGE)\n");
    }
}

/**
 * @brief 根据ADC电压值判断按键类型
 *
 * @param voltage ADC电压值 (mV)
 * @return KeyType_e 按键类型
 */
static KeyType_e Inf_FourwayKey_GetKeyTypeByVoltage(uint32_t voltage)
{
    if (voltage >= KEY_VOLTAGE_NONE_MIN && voltage <= KEY_VOLTAGE_NONE_MAX) {
        return KEY_TYPE_NONE;
    }
    else if (voltage >= KEY_VOLTAGE_UP_MIN && voltage <= KEY_VOLTAGE_UP_MAX) {
        return KEY_TYPE_UP;
    }
    else if (voltage >= KEY_VOLTAGE_DOWN_MIN && voltage <= KEY_VOLTAGE_DOWN_MAX) {
        return KEY_TYPE_DOWN;
    }
    else if (voltage >= KEY_VOLTAGE_LEFT_MIN && voltage <= KEY_VOLTAGE_LEFT_MAX) {
        return KEY_TYPE_LEFT;
    }
    else if (voltage >= KEY_VOLTAGE_RIGHT_MIN && voltage <= KEY_VOLTAGE_RIGHT_MAX) {
        return KEY_TYPE_RIGHT;
    }
    else if (voltage <= KEY_VOLTAGE_MIDDLE_MAX) {
        return KEY_TYPE_MIDDLE;
    }
    else {
        return KEY_TYPE_NONE; // 默认无按键
    }
}

/**
 * @brief 按键状态机处理
 *
 * @param keyType 按键类型
 * @param isPressed 是否按下
 */
static void Inf_FourwayKey_StateMachine(KeyType_e keyType, bool isPressed)
{
    if (keyType == KEY_TYPE_NONE || keyType >= KEY_TYPE_MAX) {
        return;
    }

    KeyStatus_t *pKeyStatus = &keyStatus[keyType];

    switch (pKeyStatus->state) {
    case KEY_STATE_IDLE:
        if (isPressed) {
            /* 按键按下，进入消抖状态 */
            pKeyStatus->state          = KEY_STATE_DEBOUNCE;
            pKeyStatus->pressTime      = 0;
            pKeyStatus->continuousTime = 0;
        }
        break;

    case KEY_STATE_DEBOUNCE:
        if (isPressed) {
            /* 按键仍然按下 */
            pKeyStatus->pressTime++;
            if (pKeyStatus->pressTime >= KEY_DEBOUNCE_TIME) {
                /* 消抖完成，进入短按状态 */
                pKeyStatus->state     = KEY_STATE_SHORT_PRESS;
                pKeyStatus->isPressed = true;
                pKeyStatus->pressTime = 0;

                /* 连续模式下，立即触发一次连续事件 */
                if (pKeyStatus->mode == KEY_MODE_CONTINUOUS) {
                    pKeyStatus->event = KEY_EVENT_CONTINUOUS;

                    /* 调用回调函数 */
                    if (keyCallback != NULL) {
                        keyCallback(keyType, KEY_EVENT_CONTINUOUS);
                    }
                }
            }
        }
        else {
            /* 按键释放，回到空闲状态 */
            pKeyStatus->state     = KEY_STATE_IDLE;
            pKeyStatus->pressTime = 0;
        }
        break;

    case KEY_STATE_SHORT_PRESS:
        if (isPressed) {
            /* 按键仍然按下 */
            pKeyStatus->pressTime++;

            /* 连续模式下，定期触发连续事件 */
            if (pKeyStatus->mode == KEY_MODE_CONTINUOUS) {
                pKeyStatus->continuousTime++;
                if (pKeyStatus->continuousTime >= continuousInterval) {
                    pKeyStatus->event          = KEY_EVENT_CONTINUOUS;
                    pKeyStatus->continuousTime = 0;

                    /* 调用回调函数 */
                    if (keyCallback != NULL) {
                        keyCallback(keyType, KEY_EVENT_CONTINUOUS);
                    }
                }
            }

            /* 检查是否达到长按阈值 */
            if (pKeyStatus->pressTime >= KEY_LONG_PRESS_THRESHOLD) {
                /* 达到长按阈值，触发长按事件 */
                pKeyStatus->state = KEY_STATE_LONG_PRESS;

                /* 单次模式下，触发长按事件 */
                if (pKeyStatus->mode == KEY_MODE_SINGLE) {
                    pKeyStatus->event = KEY_EVENT_LONG_PRESS;

                    /* 调用回调函数 */
                    if (keyCallback != NULL) {
                        keyCallback(keyType, KEY_EVENT_LONG_PRESS);
                    }
                }
            }
        }
        else {
            /* 按键释放 */
            pKeyStatus->state     = KEY_STATE_RELEASE;
            pKeyStatus->isPressed = false;

            /* 单次模式下，触发短按事件 */
            if (pKeyStatus->mode == KEY_MODE_SINGLE) {
                pKeyStatus->event = KEY_EVENT_SHORT_PRESS;

                /* 调用回调函数 */
                if (keyCallback != NULL) {
                    keyCallback(keyType, KEY_EVENT_SHORT_PRESS);
                }
            }

            /* 连续模式下，触发释放事件 */
            if (pKeyStatus->mode == KEY_MODE_CONTINUOUS) {
                pKeyStatus->event = KEY_EVENT_RELEASE;

                /* 调用回调函数 */
                if (keyCallback != NULL) {
                    keyCallback(keyType, KEY_EVENT_RELEASE);
                }
            }
        }
        break;

    case KEY_STATE_LONG_PRESS:
        if (isPressed) {
            /* 按键仍然按下 */

            /* 连续模式下，定期触发连续事件 */
            if (pKeyStatus->mode == KEY_MODE_CONTINUOUS) {
                pKeyStatus->continuousTime++;
                if (pKeyStatus->continuousTime >= continuousInterval) {
                    pKeyStatus->event          = KEY_EVENT_CONTINUOUS;
                    pKeyStatus->continuousTime = 0;

                    /* 调用回调函数 */
                    if (keyCallback != NULL) {
                        keyCallback(keyType, KEY_EVENT_CONTINUOUS);
                    }
                }
            }
        }
        else {
            /* 按键释放 */
            pKeyStatus->state     = KEY_STATE_RELEASE;
            pKeyStatus->isPressed = false;

            /* 触发释放事件 */
            pKeyStatus->event = KEY_EVENT_RELEASE;

            /* 调用回调函数 */
            if (keyCallback != NULL) {
                keyCallback(keyType, KEY_EVENT_RELEASE);
            }
        }
        break;

    case KEY_STATE_RELEASE:
        /* 释放状态自动回到空闲状态 */
        pKeyStatus->state          = KEY_STATE_IDLE;
        pKeyStatus->pressTime      = 0;
        pKeyStatus->continuousTime = 0;
        break;

    default:
        /* 异常状态，重置为空闲状态 */
        pKeyStatus->state          = KEY_STATE_IDLE;
        pKeyStatus->pressTime      = 0;
        pKeyStatus->continuousTime = 0;
        pKeyStatus->isPressed      = false;
        break;
    }
}

static void Inf_ForewayKey_DisplayPressedKeyType(KeyType_e keyType)
{
    switch (keyType) {
    case KEY_TYPE_UP:     LOG("UP\n"); break;
    case KEY_TYPE_DOWN:   LOG("DOWN\n"); break;
    case KEY_TYPE_LEFT:   LOG("LEFT\n"); break;
    case KEY_TYPE_RIGHT:  LOG("RIGHT\n"); break;
    case KEY_TYPE_MIDDLE: LOG("MIDDLE\n"); break;
    }
}
